﻿using System.Collections.Immutable;
using System.Diagnostics;

namespace DimensionsHelper.LanguageService.Syntax;

public class ModuleSignature : Declaration
{
    private SyntaxList<ClassSignature>? _classes;
    private SyntaxList<ConstantSignature>? _constants;
    private SyntaxList<EnumSignature>? _enums;
    private SyntaxList<FunctionSignature>? _functions;

    private SyntaxList<InterfaceSignature>? _interfaces;

    internal ModuleSignature(SyntaxToken declareKeywordToken, QualifiedName qualifiedName,
        SyntaxNode? parent) :
        base(SyntaxKinds.ModuleSignature, declareKeywordToken,
            qualifiedName.IsEmpty ? Identifier.Default : qualifiedName.Last(), parent)
    {
        QualifiedName = qualifiedName;
    }


    /// <summary>
    ///     全限定名
    /// </summary>
    public QualifiedName QualifiedName { get; }


    public override string Name => QualifiedName.GetFullName();


    public override bool IsSignature => true;


    public override bool IsTypeSignature => true;


    protected override string GetFullName()
    {
        return QualifiedName.GetFullName();
    }


    /// <summary>
    ///     已添加的接口签名列表
    /// </summary>
    public ImmutableArray<InterfaceSignature> GetInterfaces()
    {
        return _interfaces?.ToImmutableArray() ?? ImmutableArray<InterfaceSignature>.Empty;
    }


    /// <summary>
    ///     已添加的类签名列表
    /// </summary>
    public ImmutableArray<ClassSignature> GetClasses()
    {
        return _classes?.ToImmutableArray() ?? ImmutableArray<ClassSignature>.Empty;
    }


    /// <summary>
    ///     已添加的枚举签名列表
    /// </summary>
    public ImmutableArray<EnumSignature> GetEnums()
    {
        return _enums?.ToImmutableArray() ?? ImmutableArray<EnumSignature>.Empty;
    }


    /// <summary>
    ///     已添加的常量签名列表
    /// </summary>
    public ImmutableArray<ConstantSignature> GetConstants()
    {
        return _constants?.ToImmutableArray() ?? ImmutableArray<ConstantSignature>.Empty;
    }


    /// <summary>
    ///     已添加的函数签名列表
    /// </summary>
    public ImmutableArray<FunctionSignature> GetFunctions()
    {
        return _functions?.ToImmutableArray() ?? ImmutableArray<FunctionSignature>.Empty;
    }


    /// <summary>
    ///     添加新的常量签名
    /// </summary>
    public void AddConstant(ConstantSignature constant)
    {
        AddChildMember(ref _constants, constant);
        constant.ContainingModule = this;
    }


    /// <summary>
    ///     查找指定名称的常量定义
    /// </summary>
    /// <param name="name">定义名，不区分大小写</param>
    public ConstantSignature? GetConstant(string name)
    {
        return FindDeclaration(_constants, name);
    }


    /// <summary>
    ///     添加新的函数签名
    /// </summary>
    public void AddFunction(FunctionSignature function)
    {
        AddChildMember(ref _functions, function);
    }


    /// <summary>
    ///     查找指定名称的函数定义
    /// </summary>
    /// <param name="functionName">函数名</param>
    public FunctionSignature? GetFunction(string functionName)
    {
        return FindDeclaration(_functions, functionName);
    }


    /// <summary>
    ///     添加新的类签名
    /// </summary>
    /// <param name="classSignature">已有的类型签名</param>
    public void AddClass(ClassSignature classSignature)
    {
        AddChildMember(ref _classes, classSignature);
        classSignature.ContainingModule = this;
    }


    /// <summary>
    ///     查找指定名称的类定义
    /// </summary>
    /// <param name="className">定义名，不区分大小写</param>
    public ClassSignature? GetClass(string className)
    {
        return FindDeclaration(_classes, className);
    }


    /// <summary>
    ///     添加新的接口签名
    /// </summary>
    public void AddInterface(InterfaceSignature interfaceSignature)
    {
        AddChildMember(ref _interfaces, interfaceSignature);
        interfaceSignature.ContainingModule = this;
    }


    /// <summary>
    ///     查找指定名称的接口定义
    /// </summary>
    /// <param name="interfaceName">定义名，不区分大小写</param>
    public InterfaceSignature? GetInterface(string interfaceName)
    {
        return FindDeclaration(_interfaces, interfaceName);
    }


    /// <summary>
    ///     添加新的枚举签名
    /// </summary>
    /// <param name="enumSignature">已有的枚举类型签名</param>
    public void AddEnum(EnumSignature enumSignature)
    {
        AddChildMember(ref _enums, enumSignature);
        enumSignature.ContainingModule = this;
    }


    /// <summary>
    ///     查找指定名称的枚举定义
    /// </summary>
    /// <param name="enumName">定义名，不区分大小写</param>
    public EnumSignature? GetEnum(string enumName)
    {
        return FindDeclaration(_enums, enumName);
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        Accept(visitor, DeclareKeywordToken, QualifiedName);
        AcceptList(visitor, _interfaces);
        AcceptList(visitor, _classes);
        AcceptList(visitor, _enums);
        AcceptList(visitor, _constants);
        AcceptList(visitor, _functions);
    }
}


public static partial class NodeFactory
{
    public static ModuleSignature CreateModuleSignature(SyntaxNode? parent,
        SyntaxToken declareKeywordToken,
        QualifiedName qualifiedName, IEnumerable<InterfaceSignature>? interfaces,
        IEnumerable<ClassSignature>? classes, IEnumerable<EnumSignature>? enums,
        IEnumerable<FunctionSignature>? functions, IEnumerable<ConstantSignature>? constants)
    {
        Debug.Assert(declareKeywordToken.IsNode(SyntaxKinds.ModuleKeywordToken));
        ModuleSignature signature = new(declareKeywordToken, qualifiedName, parent);

        if (interfaces != null)
        {
            foreach (InterfaceSignature item in interfaces)
            {
                signature.AddInterface(item);
            }
        }

        if (classes != null)
        {
            foreach (ClassSignature item in classes)
            {
                signature.AddClass(item);
            }
        }

        if (enums != null)
        {
            foreach (EnumSignature item in enums)
            {
                signature.AddEnum(item);
            }
        }

        if (functions != null)
        {
            foreach (FunctionSignature func in functions)
            {
                signature.AddFunction(func);
            }
        }

        if (constants == null)
        {
            return signature;
        }

        foreach (ConstantSignature item in constants)
        {
            signature.AddConstant(item);
        }

        return signature;
    }
}